<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<script src="../dist/iife/spine-webgl.js"></script>
<style>
	* {
		margin: 0;
		padding: 0;
	}
</style>

<body>
	<canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas>
	<script>
        class App {
            constructor() {
                this.skeleton = null;
                this.animationState = null;
                this.draggableBones = [];
                this.draggedBone = null;
            }

            loadAssets(canvas) {
                canvas.assetManager.loadBinary("/assets/stretchyman-pro.skel");
                canvas.assetManager.loadTextureAtlas("/assets/stretchyman-pma.atlas");
            }

            initialize(canvas) {
                let assetManager = canvas.assetManager;
                var atlas = assetManager.require("/assets/stretchyman-pma.atlas");
                var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
                var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
                skeletonBinary.scale = 1;
                var skeletonData = skeletonBinary.readSkeletonData(assetManager.require("/assets/stretchyman-pro.skel"));
                this.skeleton = new spine.Skeleton(skeletonData);
                var animationStateData = new spine.AnimationStateData(skeletonData);
                this.animationState = new spine.AnimationState(animationStateData);

                // Find the bones that should be draggable
                let draggableBoneNames = [
                    "back-leg-ik-target",
                    "front-leg-ik-target",
                    "back-arm-ik-target",
                    "front-arm-ik-target",
                    "hip",
                    "neck2"
                ];
                for (let boneName of draggableBoneNames) {
                    let bone = this.skeleton.findBone(boneName);
                    if (bone == null) throw Error("Couldn't find bone " + boneName);
                    this.draggableBones.push(bone)
                }

                // Setup an input listener on the canvas to process touch/mouse events.
                canvas.input.addListener({
                    down: (x, y) => {
                        // Calculate the mouse position in the coordinate space of the camera, aka world space.
                        // The skeleton and its bones live in the same coordinate space.
                        let mousePosition = new spine.Vector3(x, y);
                        canvas.renderer.camera.screenToWorld(mousePosition, canvas.htmlCanvas.clientWidth, canvas.htmlCanvas.clientHeight);

                        // Find the first bone within a radius of 20 pixels to the mouse position
                        this.selectedBone = null;
                        for (let bone of this.draggableBones) {
                            if (mousePosition.distance(new spine.Vector3(bone.worldX, bone.worldY, 0)) < 20) {
                                this.selectedBone = bone;
                                break;
                            }
                        }
                    },
                    dragged: (x, y) => {
                        // If no bone was selected, bail.
                        if (this.selectedBone == null) return;

                        // Calculate the mouse position in the coordinate space of the camera, aka world space.
                        // The skeleton and its bones live in this coordinate space.
                        let mousePosition = new spine.Vector3(x, y);
                        canvas.renderer.camera.screenToWorld(mousePosition, canvas.htmlCanvas.clientWidth, canvas.htmlCanvas.clientHeight);

                        if (this.selectedBone.parent != null) {
                            // If the bone to be dragged has a parent, transform the mouse world position to
                            // the parent bone's coordinate system, and set the bone's position accordingly.
                            let position = new spine.Vector2(mousePosition.x, mousePosition.y);
                            this.selectedBone.parent.worldToLocal(position);
                            this.selectedBone.x = position.x;
                            this.selectedBone.y = position.y;
                        } else {
                            // If the dragged bone has no parent, it's the root bone and we can simply set its
                            // position to the mouse world position.
                            this.selectedBone.x = mousePosition.x;
                            this.selectedBone.y = mousePosition.y;
                        }
                    }
                })
            }

            update(canvas, delta) {
                this.animationState.update(delta);
                this.animationState.apply(this.skeleton);
                this.skeleton.updateWorldTransform(spine.Physics.update);
            }

            render(canvas) {
                let renderer = canvas.renderer;
                renderer.resize(spine.ResizeMode.Expand);
                canvas.clear(0.2, 0.2, 0.2, 1);

                renderer.begin();
                renderer.drawSkeleton(this.skeleton, true);

                // Draw a circle with a radius of 20 pixels around each draggable bone
                let boneColor = new spine.Color(1, 0, 0, 0.5);
                let selectedBoneColor = new spine.Color(0, 1, 0, 0.5);
                for (let bone of this.draggableBones) {
                    renderer.circle(true, bone.worldX, bone.worldY, 20, bone == this.selectedBone ? selectedBoneColor : boneColor);
                }

                renderer.end();
            }
        }

        new spine.SpineCanvas(document.getElementById("canvas"), {
            app: new App()
        })
    </script>
</body>

</html>